package com.yanqu.road.server.manager.grandchild;

import com.yanqu.road.entity.grandchild.GrandChildExamData;
import com.yanqu.road.entity.grandchild.GrandChildExamOpenTime;
import com.yanqu.road.entity.grandchild.JoinExamGrandChild;
import com.yanqu.road.entity.grandchild.ServerExamData;
import com.yanqu.road.entity.player.UserBaseInfo;
import com.yanqu.road.logic.bussiness.grandchild.GrandChildBussiness;
import com.yanqu.road.logic.config.GameConfig;
import com.yanqu.road.logic.pb.PlayerBasePb;
import com.yanqu.road.utils.YanQuMessageUtils;
import com.yanqu.road.pb.grandchild.GrandChildProto;
import com.yanqu.road.server.TempMgr;
import com.yanqu.road.server.logic.MessageHelper;
import com.yanqu.road.server.manager.user.CrossUserMgr;
import com.yanqu.road.message.YanQuMessage;
import com.yanqu.road.server.protocol.ClientProtocol;
import com.yanqu.road.server.protocol.GameErrorCode;
import com.yanqu.road.server.protocol.GameProtocol;
import com.yanqu.road.utils.date.DateHelper;
import com.yanqu.road.utils.string.StringUtils;
import org.apache.mina.util.ConcurrentHashSet;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;

public class GrandChildMgr extends TempMgr {

    // 分组ID，锁
    private static final Map<Integer, Object> lockMap = new ConcurrentHashMap<>();

    // 分组ID，当前科举数据
    private static Map<Integer, GrandChildExamRoom> curExamRoomMap; //用getCurExam获取
    // 科举ID，科举数据
    private static Map<Long, GrandChildExamRoom> examRoomMap;

    // 最大科举ID
    private static AtomicLong maxExamId;

    // 区服ID，区服科举统计数据
    private static Map<Long, ServerExamData> serverExamDataMap;

    /**
     * 获取锁
     */
    private static Object getLock(int groupId) {
        if (!lockMap.containsKey(groupId)) {
            synchronized (lockMap) {
                if (!lockMap.containsKey(groupId)) {
                    lockMap.put(groupId, new Object());
                }
            }
        }
        return lockMap.get(groupId);
    }

    /**
     * 进入科举考场
     */
    public static int enterExam(long serverId, long userId, int pageNo) {

        int groupId = GrandChildExamConfigMgr.getGroupId(serverId);
        if (groupId == 0) {
            return GameErrorCode.E_GRAND_CHILD_EXAM_NO_OPEN;
        }
        GrandChildExamRoom examRoom = getCurExam(groupId);
        if (examRoom == null) {
            return GameErrorCode.E_GRAND_CHILD_EXAM_NO_OPEN;
        }
        if (!examRoom.getServerIdSet().contains(serverId)) {
            return GameErrorCode.E_GRAND_CHILD_EXAM_GROUP_CHANGE;
        }
        if (examRoom.isFinish()) {
            return GameErrorCode.E_GRAND_CHILD_EXAM_HAD_END;
        }

        // 进入考场
        examRoom.enterExam(serverId, userId, pageNo);
        return 0;
    }

    /**
     * 获取当前科举
     *
     * @return groupId不存在时返回null
     */
    public static GrandChildExamRoom getCurExam(int groupId) {
        if (!curExamRoomMap.containsKey(groupId)) {
            createNextGrandChildExamRoom(groupId);
        }

        // 判断下是否结束
        GrandChildExamRoom examRoom = curExamRoomMap.get(groupId);
        if (examRoom != null) {
            if (examRoom.isFull() && !examRoom.isFinish()) {
                examRoom.finishExam();
            }
            if (examRoom.isFinish()) {
                createNextGrandChildExamRoom(groupId);
            }
        }

        return curExamRoomMap.get(groupId);
    }

    /**
     * 生成一场科举
     */
    private static void createNextGrandChildExamRoom(int groupId) {

        // 不在生成时间内
        GrandChildExamOpenTime curOpenTime = GrandChildExamConfigMgr.getCurOpenTime();
        if (curOpenTime == null) {
            return;
        }

        synchronized (getLock(groupId)) {

            // 还有未结束的，不能生成
            if (curExamRoomMap.containsKey(groupId) && !curExamRoomMap.get(groupId).isFinish()) {
                return;
            }

            // 没有这个分组了，不能生成
            List<Long> serverList = GrandChildExamConfigMgr.getServerList(groupId);
            if (serverList.isEmpty()) {
                return;
            }

            // 考场基础数据
            GrandChildExamData grandChildExamData = new GrandChildExamData();
            grandChildExamData.setGlobalId(maxExamId.incrementAndGet());
            grandChildExamData.setGroupId(groupId);
            grandChildExamData.setServerList(new ConcurrentHashSet<>(serverList));
            grandChildExamData.setOpenTime(System.currentTimeMillis());
            grandChildExamData.setFinishTime(0L);
            grandChildExamData.setOpenTimeParam(curOpenTime.getParam());
            grandChildExamData.setInsertOption();

            // 生成考场
            GrandChildExamRoom examRoom = new GrandChildExamRoom(grandChildExamData, new ArrayList<>());

            // 加次数
            addServerExamData(examRoom.getGlobalId(), examRoom.getServerIdSet());
            // 加到Map
            examRoomMap.put(examRoom.getGlobalId(), examRoom);
            curExamRoomMap.put(groupId, examRoom);
        }
    }

    /**
     * 添加区服科举记录
     */
    public static void addServerExamData(long globalId, Set<Long> serverIdSet) {
        for (long serverId : serverIdSet) {
            ServerExamData serverExamData = getServerExamData(serverId);
            serverExamData.addExamRecord(globalId, 100);
        }
    }

    /**
     * 移除区服科举空记录
     */
    public static void removeServerExamData(long globalId, Set<Long> serverIdSet) {
        for (long serverId : serverIdSet) {
            ServerExamData serverExamData = getServerExamData(serverId);
            serverExamData.removeEmptyExam(globalId);
        }
    }

    /**
     * 获取区服科举统计数据
     */
    public static ServerExamData getServerExamData(long serverId) {
        if (!serverExamDataMap.containsKey(serverId)) {
            synchronized (serverExamDataMap) {
                if (!serverExamDataMap.containsKey(serverId)) {
                    ServerExamData data = new ServerExamData();
                    data.setServerId(serverId);
                    data.setExamTimes(0);
                    data.setGlobalList(new ArrayList<>());
                    data.setInsertOption();
                    serverExamDataMap.put(serverId, data);
                }
            }
        }
        return serverExamDataMap.get(serverId);
    }

    /**
     * 加入科举
     */
    public static int joinExam(long serverId, long globalId, JoinExamGrandChild child) {
        // 是否有配置分组跨服
        int groupId = GrandChildExamConfigMgr.getGroupId(serverId);
        if (groupId == 0) {
            return GameErrorCode.E_GRAND_CHILD_EXAM_NO_OPEN;
        }

        // 科举考试看看在不在
        GrandChildExamRoom examRoom = getCurExam(groupId);
        if (examRoom == null) {
            return GameErrorCode.E_GRAND_CHILD_EXAM_NO_OPEN;
        }

        // 参加
        return examRoom.joinExam(globalId, serverId, child);
    }

    /**
     * 获取科举结果
     */
    public static int getExamResult(long serverId, long userId, long globalId, int type) {
        GrandChildExamRoom examRoom = examRoomMap.get(globalId);
        if (examRoom == null) {
            return GameErrorCode.E_GRAND_CHILD_EXAM_NO_EXIST;
        }
        if (!examRoom.isFinish()) {
            return GameErrorCode.E_GRAND_CHILD_EXAM_NO_END;
        }
        examRoom.getResult(serverId, userId, type);
        return 0;
    }

    /**
     * 获取皇榜
     */
    public static void getHistoryExam(long serverId, long userId) {
        ServerExamData serverExamData = getServerExamData(serverId);
        GrandChildProto.ExamHistoryRespMsg.Builder builder = GrandChildProto.ExamHistoryRespMsg.newBuilder();

        if (serverExamData != null) {

            ArrayList<Long> examNoList = new ArrayList<>(serverExamData.getGlobalList());
            long curSession = serverExamData.getExamTimes(); // 当前届数（可能已结束）
            int count = GameConfig.GRAND_CHILD_HISTORY_EXAM_COUNT;

            // 当前届正在进行，皇榜届数减一
            if (examNoList.size() > 0) {
                GrandChildExamRoom lastExam = examRoomMap.get(examNoList.get(examNoList.size() - 1));
                if (lastExam != null && !lastExam.isFinish()) {
                    curSession--;
                }
            }

            // 倒叙找，找到数量够为止
            for (int i = examNoList.size() - 1; i >= 0; i--) {
                long examNo = examNoList.get(i);
                GrandChildExamRoom examRoom = examRoomMap.get(examNo);
                if (examRoom != null) {
                    GrandChildProto.ExamHistorySimpleMsg.Builder tmp = parseExamHistorySimpleMsg(examRoom, userId, curSession);
                    if (tmp != null) {
                        builder.addData(tmp);
                        curSession--;

                        if (builder.getDataCount() >= count || curSession <= 0) {
                            break;
                        }
                    }
                }
            }
        }

        // 返回
        YanQuMessage message = YanQuMessageUtils.buildMessage(ClientProtocol.U_GRAND_CHILD_GET_HISTORY_EXAM, builder);
        MessageHelper.sendPacket(serverId, userId, message);
    }

    /**
     * 科举数据转换皇榜
     */
    private static GrandChildProto.ExamHistorySimpleMsg.Builder parseExamHistorySimpleMsg(GrandChildExamRoom examRoom, long userId, long session) {
        if (!examRoom.isFinish()) {
            return null;
        }

        JoinExamGrandChild zhuangYuan = null; // 状元
        boolean join = false; // 自己是否参加

        List<JoinExamGrandChild> list = new ArrayList<>(examRoom.getJoinExamGrandChildren());
        for (JoinExamGrandChild child : list) {
            if (child.getTitle() == 1) {
                zhuangYuan = child;
                break;
            }
        }
        for (JoinExamGrandChild child : list) {
            if (child.getUserId() == userId) {
                join = true;
                break;
            }
        }

        if (zhuangYuan == null) {
            return null;
        }

        UserBaseInfo userBaseInfo = CrossUserMgr.getUserBaseInfo(zhuangYuan.getUserId());
        if (userBaseInfo == null) {
            userBaseInfo = new UserBaseInfo();
        }

        GrandChildProto.ExamPupilResultMsg.Builder msg = GrandChildProto.ExamPupilResultMsg.newBuilder();
        msg.setAppearanceId(zhuangYuan.getAppearanceId());
        msg.setUserBaseInfo(PlayerBasePb.parsePlayerBaseTempMsg(userBaseInfo));
        msg.setName(zhuangYuan.getNickName());
        msg.setEarnSpeed(zhuangYuan.getEarnSpeed().toString());
        msg.setTitle(zhuangYuan.getTitle());
        msg.setUserId(zhuangYuan.getUserId());
        msg.setId(zhuangYuan.getId());

        GrandChildProto.ExamHistorySimpleMsg.Builder builder = GrandChildProto.ExamHistorySimpleMsg.newBuilder();
        builder.setExamNo(examRoom.getGlobalId() + "");
        builder.setData(msg);
        builder.setJoin(join);
        builder.setSession(session);
        return builder;
    }

    /**
     * 同步加入科举消息
     */
    public static void syncJoinExamMsg() {
        for (GrandChildExamRoom examRoom : curExamRoomMap.values()) {
            examRoom.syncExamJoinMsg();
        }
    }

    /**
     * 检查分组变化
     * （检查时间：1启动，2分组变更）
     */
    public static void checkGroupChange() {
        // 分组ID，区服ID
        Map<Integer, List<Long>> listMap = GrandChildExamConfigMgr.getGroupServerMap();

        for (GrandChildExamRoom examRoom : curExamRoomMap.values()) {
            int groupId = examRoom.getGroupId();
            List<Long> newServerList = listMap.get(groupId);
            Set<Long> oldList = examRoom.getServerIdSet();
            boolean listChange = false;

            // 判断分组变化
            if (newServerList == null) {
                listChange = true;
                curExamRoomMap.remove(groupId); // 移除
            } else if (oldList.size() != newServerList.size()) {
                listChange = true;
            } else {
                for (long serverId : newServerList) {
                    if (!oldList.contains(serverId)) {
                        listChange = true;
                        break;
                    }
                }
            }

            // 分组结束
            if (listChange) {
                examRoom.finishExam();
            }
        }
        for (Integer groupId : listMap.keySet()) {
            // 榜单刷新
            GrandChildRankMgr.getRankListModel(groupId, true);
        }
    }

    /**
     * 结束过期科举
     * 1.昨天延期到24点的，2跨时间区间的
     */
    public static void endExpireExam() {
        // 当前未开放，过期昨天开启的
        GrandChildExamOpenTime curOpenTime = GrandChildExamConfigMgr.getCurOpenTime();
        if (curOpenTime == null) {
            long zeroTime = DateHelper.getTodayZeroTimeStamp();
            for (GrandChildExamRoom examRoom : curExamRoomMap.values()) {
                if (!examRoom.isFinish() && examRoom.getOpenTime() < zeroTime) {
                    examRoom.finishExam();
                }
            }
            return;
        }

        // 当前开放，过期跨时间区间的
        for (GrandChildExamRoom examRoom : curExamRoomMap.values()) {
            if (!examRoom.isFinish() && examRoom.getOpenTime() < curOpenTime.getBegin()) {
                examRoom.finishExam();
            }
        }
    }

    private static void reloadExamData() {
        // 加载 区服科举数据
        Map<Long, ServerExamData> tmpServerExamDataMap = GrandChildBussiness.getServerExamDataMap();

        // 加载 最近科举数据
        long maxId = 0;
        Map<Long, GrandChildExamRoom> tmpExamRoomMap = new ConcurrentHashMap<>();

        long minGlobalId = Long.MAX_VALUE; // 拿最小ID，加载≥这个ID的数据
        for (ServerExamData serverExamData : tmpServerExamDataMap.values()) {
            List<Long> globalList = serverExamData.getGlobalList();
            if (!globalList.isEmpty()) {
                minGlobalId = Math.min(globalList.get(0), minGlobalId);
            }
        }
        Map<Long, GrandChildExamData> examDataMap = GrandChildBussiness.getGrandChildExamDataMap(minGlobalId);
        Map<Long, List<JoinExamGrandChild>> joinDataMap = GrandChildBussiness.getJoinExamGrandChildMap(minGlobalId);

        for (GrandChildExamData examData : examDataMap.values()) { // 合并科举数据和参与孙子数据
            List<JoinExamGrandChild> joinList = joinDataMap.get(examData.getGlobalId());
            if (joinList == null) {
                joinList = new ArrayList<>();
            }
            GrandChildExamRoom tmp = new GrandChildExamRoom(examData, joinList);
            tmpExamRoomMap.put(examData.getGlobalId(), tmp);

            maxId = Math.max(examData.getGlobalId(), maxId);
        }

        // 加载 当前科举数据
        Map<Integer, List<GrandChildExamRoom>> groupRoomMap = new ConcurrentHashMap<>();
        for (GrandChildExamRoom examRoom : tmpExamRoomMap.values()) { // 按groupId把未结束的分类
            if (!examRoom.isFinish()) {
                if (!groupRoomMap.containsKey(examRoom.getGroupId())) {
                    groupRoomMap.put(examRoom.getGroupId(), new ArrayList<>());
                }
                groupRoomMap.get(examRoom.getGroupId()).add(examRoom);
            }
        }

        Map<Integer, GrandChildExamRoom> tmpCurExamRoomMap = new ConcurrentHashMap<>();
        for (Map.Entry<Integer, List<GrandChildExamRoom>> entry : groupRoomMap.entrySet()) { // 遍历每个分组，设置当前科举
            int groupId = entry.getKey();
            List<GrandChildExamRoom> list = entry.getValue();
            if (list.size() != 1) { // 如果某个分组有多个未结束的
                long maxGlobalId = list.stream().mapToLong(GrandChildExamRoom::getGlobalId).max().getAsLong();
                for (GrandChildExamRoom examRoom : list) {
                    if (examRoom.getGlobalId() != maxGlobalId) {
                        examRoom.finishExam(); // 强制结束有问题的科举
                    } else {
                        tmpCurExamRoomMap.put(groupId, examRoom); // 正常科举
                    }
                }
            } else {
                tmpCurExamRoomMap.put(groupId, list.get(0)); // 正常科举
            }
        }

        maxExamId = new AtomicLong(maxId);
        serverExamDataMap = tmpServerExamDataMap;
        examRoomMap = tmpExamRoomMap;
        curExamRoomMap = tmpCurExamRoomMap;
    }

    /**
     * 同步科举配置状态
     */
    public static void syncExamConfigMsg(List<Long> serverList) {
        for (long serverId : serverList) {
            GrandChildProto.GrandChildSyncExamGroupRespMsg.Builder builder = getExamConfigMsg(serverId);
            YanQuMessage yanQuMessage = YanQuMessageUtils.buildMessage(GameProtocol.S_GRAND_CHILD_SYNC_EXAM_GROUP, builder);
            MessageHelper.sendPacket(serverId, 0, yanQuMessage);
        }
    }

    /**
     * 获取科举配置Msg
     */
    public static GrandChildProto.GrandChildSyncExamGroupRespMsg.Builder getExamConfigMsg(long serverId) {
        int groupId = GrandChildExamConfigMgr.getGroupId(serverId);
        return getExamConfigMsg(groupId);
    }

    /**
     * 获取科举配置Msg
     */
    public static GrandChildProto.GrandChildSyncExamGroupRespMsg.Builder getExamConfigMsg(int groupId) {
        List<Long> serverList = GrandChildExamConfigMgr.getServerList(groupId);
        boolean open = true;
        if (serverList.isEmpty()) {
            open = false;
        } else {
            GrandChildExamRoom curExam = getCurExam(groupId);
            if (curExam == null || curExam.isFinish()) {
                open = false;
            }
        }

        GrandChildProto.GrandChildSyncExamGroupRespMsg.Builder builder = GrandChildProto.GrandChildSyncExamGroupRespMsg.newBuilder();
        builder.addAllServerList(serverList);
        builder.addAllTimeList(StringUtils.stringToStringList(GameConfig.GRAND_CHILD_EXAM_OPEN_TIME, "\\|"));
        builder.setOpen(open);
        builder.setOpenTime(GrandChildExamConfigMgr.getBeginTime());
        return builder;
    }


    @Override
    public boolean init() throws Exception {
        return reload();
    }

    @Override
    public boolean reloadConfig() throws Exception {
        return true;
    }

    @Override
    public boolean reloadData() throws Exception {
        // 重新加载数据
        reloadExamData();
        // 检查下分组变化
        checkGroupChange();
        return true;
    }

    @Override
    public boolean save() {
        for (GrandChildExamRoom examRoom : examRoomMap.values()) {
            examRoom.save();
        }
        for (ServerExamData serverExamData : serverExamDataMap.values()) {
            if (serverExamData.isInsertOption()) {
                GrandChildBussiness.addServerExamData(serverExamData);
            } else if (serverExamData.isUpdateOption()) {
                GrandChildBussiness.updateServerExamData(serverExamData);
            }
        }
        return true;
    }

    @Override
    public boolean stop() {
        return true;
    }

    // ===================================================

    // 待确认结算的科举    不入库
    private static final Map<Long, Set<Long>> toHandleExamMap = new ConcurrentHashMap<>();

    public static void addToHandleExam(long examNo, Set<Long> serverList) {
        synchronized (toHandleExamMap) {
            toHandleExamMap.put(examNo, serverList);
        }
    }

    public static void removeToHandleExam(long examNo, long serverId) {
        synchronized (toHandleExamMap) {
            if (toHandleExamMap.containsKey(examNo)) {
                toHandleExamMap.get(examNo).remove(serverId);
                if (toHandleExamMap.get(examNo).isEmpty()) {
                    toHandleExamMap.remove(examNo);
                }
            }
        }
    }

    public static void syncToHandleMsg() {
        for (Map.Entry<Long, Set<Long>> entry : toHandleExamMap.entrySet()) {
            long examNo = entry.getKey();
            GrandChildExamRoom examRoom = examRoomMap.get(examNo);
            if (entry.getValue().isEmpty() || examRoom == null) {
                continue;
            }
            examRoom.syncExamFinishMsg(new ArrayList<>(entry.getValue()));
        }
    }
}
